package org.speed.httpclient;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.impl.bootstrap.HttpServer;
import org.apache.http.impl.nio.DefaultHttpClientIODispatch;
import org.apache.http.impl.nio.bootstrap.ServerBootstrap;
import org.apache.http.impl.nio.pool.BasicNIOConnPool;
import org.apache.http.impl.nio.reactor.AbstractIOReactor;
import org.apache.http.impl.nio.reactor.BaseIOReactor;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.nio.protocol.BasicAsyncRequestConsumer;
import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
import org.apache.http.nio.protocol.BasicAsyncRequestProducer;
import org.apache.http.nio.protocol.BasicAsyncResponseConsumer;
import org.apache.http.nio.protocol.HttpAsyncExchange;
import org.apache.http.nio.protocol.HttpAsyncRequestConsumer;
import org.apache.http.nio.protocol.HttpAsyncRequestExecutor;
import org.apache.http.nio.protocol.HttpAsyncRequestHandler;
import org.apache.http.nio.protocol.HttpAsyncRequester;
import org.apache.http.nio.reactor.ConnectingIOReactor;
import org.apache.http.nio.reactor.IOEventDispatch;
import org.apache.http.nio.reactor.IOReactor;
import org.apache.http.nio.reactor.IOReactorException;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpCoreContext;
import org.apache.http.protocol.HttpProcessor;
import org.apache.http.protocol.HttpProcessorBuilder;
import org.apache.http.protocol.HttpRequestHandler;
import org.apache.http.protocol.RequestConnControl;
import org.apache.http.protocol.RequestContent;
import org.apache.http.protocol.RequestExpectContinue;
import org.apache.http.protocol.RequestTargetHost;
import org.apache.http.protocol.RequestUserAgent;

import com.google.common.collect.Lists;

/**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args ) throws Exception
    {
    	//dd1();
    	
    	
    	ServerBootstrap serverBootstrap = ServerBootstrap.bootstrap();
    	serverBootstrap.setListenerPort(8089)
    					.registerHandler("/index", new HttpAsyncRequestHandler() {

							@Override
							public HttpAsyncRequestConsumer<?> processRequest(HttpRequest request, HttpContext context)
									throws HttpException, IOException {
								
								System.out.println("processRequest");
								
								return new BasicAsyncRequestConsumer( );
							}

							@Override
							public void handle(Object data, HttpAsyncExchange httpExchange, HttpContext context)
									throws HttpException, IOException {
								
								System.out.println("handle");
							}
    						
    					})
    					.create()
    					.start();
    					;
    	
    	
    	
    	System.out.println( "Hello World!" );
    }

	private static void dd1() throws IOReactorException, InterruptedException, IOException {
		ConnectingIOReactor ioReactor = new DefaultConnectingIOReactor();
        final Thread t = new Thread(new Runnable() {
            public void run() {
                try {
                	HttpAsyncRequestExecutor protocolHandler = new HttpAsyncRequestExecutor();
                	IOEventDispatch ioEventDispatch = new DefaultHttpClientIODispatch(protocolHandler,ConnectionConfig.DEFAULT);
                    ioReactor.execute(ioEventDispatch);
                } catch (final InterruptedIOException ex) {
                    System.err.println("Interrupted");
                } catch (final IOException e) {
                    System.err.println("I/O error: " + e.getMessage());
                }
                System.out.println("Shutdown");
            }
        });
        t.start();
        
        BasicNIOConnPool pool = new BasicNIOConnPool(ioReactor, ConnectionConfig.DEFAULT);
    	pool.setDefaultMaxPerRoute(2);
        pool.setMaxTotal(2);
        
        HttpProcessor httpproc = HttpProcessorBuilder.create()
                .add(new RequestContent())
                .add(new RequestTargetHost())
                .add(new RequestConnControl())
                .add(new RequestUserAgent("Test/1.1"))
                .add(new RequestExpectContinue(true)).build();
        HttpAsyncRequester requester = new HttpAsyncRequester(httpproc);
    	
        
        HttpHost target = new HttpHost("www.apache.org");
        List<BasicAsyncRequestProducer> requestProducers = Arrays.asList(
                new BasicAsyncRequestProducer(target, new BasicHttpRequest("GET", "/index.html")),
                new BasicAsyncRequestProducer(target, new BasicHttpRequest("GET", "/foundation/index.html")),
                new BasicAsyncRequestProducer(target, new BasicHttpRequest("GET", "/foundation/how-it-works.html"))
        );
        List<BasicAsyncResponseConsumer> responseConsumers = Arrays.asList(
                new BasicAsyncResponseConsumer(),
                new BasicAsyncResponseConsumer(),
                new BasicAsyncResponseConsumer()
        );
        
        
        CountDownLatch latch = new CountDownLatch(1);
        HttpCoreContext context = HttpCoreContext.create();
        requester.executePipelined(
                target, requestProducers, responseConsumers, pool, context,
                new FutureCallback<List<HttpResponse>>() {

                    @Override
                    public void completed(final List<HttpResponse> result) {
                        latch.countDown();
                        for (final HttpResponse response: result) {
                            System.out.println(target + "->" + response.getStatusLine());
                        }
                    }

                    @Override
                    public void failed(final Exception ex) {
                        latch.countDown();
                        System.out.println(target + "->" + ex);
                    }

                    @Override
                    public void cancelled() {
                        latch.countDown();
                        System.out.println(target + " cancelled");
                    }

                }
         );
        
        latch.await();
        System.out.println("Shutting down I/O reactor");
        ioReactor.shutdown();
        System.out.println("Done");
	}
}
